
/** glibc patching source code - this is meant to provide a basic
 * compatibility layer. While it might be possible to make this more
 * functional, for the time being there appear to be no problems. */

/** remember to add new definitions to the version map file as well! */

#include <dlfcn.h>
#include <fcntl.h>

int socket_20205(int __domain, int __type, int __protocol)
{
   // don't use CLOEXEC magic! it breaks stuff! can't have nice things!
   int (*libc_socket)(int, int, int) = dlsym(RTLD_LOCAL, "socket");
   int __type2 = __type & ~(02000000);
   int socket_descr = libc_socket(__domain, __type2, __protocol);
#ifdef FD_CLOEXEC
   if (__type & (02000000))
   {
      int flags;
      if ((flags = fcntl(socket_descr, F_GETFD)) == -1)
      {
         close(socket_descr);
         return -1;
      }
      flags |= FD_CLOEXEC;
      if ((flags = fcntl(socket_descr, F_SETFD, flags)) == -1)
      {
         close(socket_descr);
         return -1;
      }
   }
#endif
   return socket_descr;
}

__asm__(".symver socket_20205,socket@GLIBC_2.2.5");

#include <stdio.h>
#include <stdlib.h>

/** usually supposed to have __libc_argv[0] in here... but we can't
 * have nice things... */
void __attribute__((noreturn)) __fortify_fail_private (msg)
   const char *msg;
{
   /* The loop is added only to keep gcc happy.  */
   while (1)
   __libc_message (2, "*** %s ***: program terminated\n",
                     msg);
}

__asm__(".symver __fortify_fail_private,__fortify_fail@GLIBC_PRIVATE");
//libc_hidden_def (__fortify_fail)

#include <time.h>
#include <errno.h>
#include <stdint.h>

int __vdso_clock_gettime_private(clockid_t clk, struct timespec *ts)
{
   int r = clock_gettime(clk, ts);
   if (!r) return r;
   if (r == -ENOSYS)
   {
      if (clk == CLOCK_REALTIME)
      {
         gettimeofday(ts);
         ts->tv_nsec = (int)ts->tv_nsec * 1000;
         return 0;
      }
      r = -EINVAL;
   }
   errno = -r;
   return -1;
}

__asm__(".symver __vdso_clock_gettime_private,__vdso_clock_gettime@GLIBC_PRIVATE");


#ifdef NO_GLIBC_2_7

#include <fcntl.h>
#include <sys/stat.h>
#include <mqueue.h>

// can't find any good information on what this actually does
mqd_t __mq_open_2_207(const char *name, int oflag)
{
   return mq_open(name, oflag);
}

__asm__(".symver __mq_open_2_207,__mq_open_2@GLIBC_2.7");


#include <stdio.h>
#include <stdarg.h>

size_t __fread_chk_207(void *__restrict ptr, size_t ptrlen,
   size_t size, size_t n, FILE *__restrict stream)
{
   size_t bytes_requested = size * n;
   if (__builtin_expect((n | size) >= (((size_t) 1) << (8 * sizeof (size_t) / 2)), 0))
      if (size != 0 && bytes_requested / size != n)
         __chk_fail ();

   if (__builtin_expect (bytes_requested > ptrlen, 0))
      __chk_fail ();

   CHECK_FILE(stream, 0);
   if (bytes_requested == 0)
      return 0;

   size_t bytes_read;
   _IO_acquire_lock(stream);
   bytes_read = _IO_sgetn(stream, (char *) ptr, bytes_requested);
   _IO_release_lock(stream);
   return bytes_requested == bytes_read ? n : bytes_read / size;
}

__asm__(".symver __fread_chk_207,__fread_chk@GLIBC_2.7");

int __isoc99_sscanf_207(const char *a, const char *b, va_list args)
{
   int i;
   va_list ap;
   va_copy(ap,args);
   i=sscanf(a,b,ap);
   va_end(ap);
   return i;
}

__asm__(".symver __isoc99_sscanf_207,__isoc99_sscanf@GLIBC_2.7");

#endif

#ifdef NO_GLIBC_2_9

#include <sys/epoll.h>

int epoll_create1_209(int flags)
{
   int fd = epoll_create(1);
   if (fd >= 0)
   {
//      if ((flags & EPOLL_CLOEXEC) == EPOLL_CLOEXEC)
//         (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
   }
   return fd;
}

__asm__(".symver epoll_create1,epoll_create1@GLIBC_2.9");

#include <unistd.h>
#include <errno.h>

int dup3_209(int oldfd, int newfd, int flags)
{
   if (newfd < 0 || newfd >= getdtablesize () || fcntl (oldfd, F_GETFD) == -1)
   {
      errno = EBADF;
      return -1;
   }

   if (newfd == oldfd)
   {
      errno = EINVAL;
      return -1;
   }
/*
   if ((flags & ~(O_CLOEXEC | O_BINARY | O_TEXT)) != 0)
   {
      errno = EINVAL;
      return -1;
   }
   if (flags & O_CLOEXEC)
   {
      int result;
      close(newfd);
      result = fcntl(oldfd, F_DUPFD_CLOEXEC, newfd);
      if (newfd < result)
      {
         close (result);
         errno = EIO;
         result = -1;
      }
      if (result < 0) return -1;
   }
   else*/ if (dup2(oldfd, newfd) < 0) return -1;
   return newfd;
}

__asm__(".symver dup3_209,dup3@GLIBC_2.9");

#endif

#ifdef NO_GLIBC_2_10

#include <sys/types.h>
#include <sys/socket.h>

int accept4_210(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags)
{
   int fd = accept(sockfd, addr, addrlen);
   /*
   if (fd >= 0)
   {
      if ((flags & SOCK_CLOEXEC) == SOCK_CLOEXEC)
         (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
      if ((flags & SOCK_NONBLOCK) == SOCK_NONBLOCK)
      {
         int fl = fcntl(fd, F_GETFL);
         (void)fcntl(fd, F_SETFL, fl | O_NONBLOCK);
      }
      errno = 0;
   }
   */
   return fd;
}

__asm__(".symver accept4_210,accept4@GLIBC_2.10");

#endif

#ifdef NO_GLIBC_2_11

#warning "Don't use precompiled pthreads with this system!"

#endif

#ifdef NO_GLIBC_2_12

#warning "Don't use precompiled pthreads with this system!"

#endif

#ifdef NO_GLIBC_2_14

void *memcpy_214(void *dest, const void *src, size_t n)
{
   memmove(dest, src, n);
   return dest;
}

__asm__(".symver memcpy_214,memcpy@GLIBC_2.14");

#endif

#ifdef NO_GLIBC_2_15

#include <sys/select.h>

unsigned long int __fdelt_chk_215 (unsigned long int d)
{
  if (d >= FD_SETSIZE)
    __chk_fail ();
  return d / __NFDBITS;
}

__asm__(".symver __fdelt_chk_215,__fdelt_chk@GLIBC_2.15");

#endif
